<template>
  <div class="vue-editor">
    <div ref="editor"></div>
    <slot name="control" :editor="editor"></slot>
  </div>
</template>
<script>
/**
 * 调用示例
 * <editor>
    <template v-slot:control="{editor}" >
        <button @click="clear(editor)">清空</button>
      </template>
    </editor>
 * 
 */

/**
 * 富文本编辑器组件
 * 使用 wangEditor 封装 文档地址：https://doc.wangeditor.com/
 *
 *
 * @prop { Number } height 富文本高度
 * @prop { String } placeholder 占位内容
 * @prop { String } defaultHtml 富文本内默认内容
 * @prop { Array } excludeMenus 富文本菜单内不要的选项
 * @prop { Array } menus 富文本菜单内的选项
 * @prop { Array } colors 编辑器的字体颜色和背景色
 * @prop { Booleab } pasteFilterStyle 关闭粘贴样式的过滤
 * @prop { Object } uploadImgConfig 图片上传地址
 * @prop { Object } uploadVideoConfig 图片上传地址
 *
 * @event change 编辑器内容改变时触发
 * @event linkImg 插入网络图片事件
 * @event onlineVideo 插入网络视频
 *
 */

import E from 'wangeditor'
import { Message } from 'element-ui'
export default {
  name: 'editor',
  props: {
    height: { type: Number, default: 500 },
    placeholder: { type: String, default: '请输入内容' },
    defaultHtml: String,
    excludeMenus: { type: Array, default: () => [] },
    menus: { type: Array, default: () => [] },
    colors: { type: Array, default: () => [] },
    uploadImgConfig: Object,
    uploadVideoConfig: Object,
  },
  data() {
    return {
      editor: null,
    }
  },
  mounted() {
    this.init()
  },
  methods: {
    // 初始化编辑器
    init() {
      const editor = new E(this.$refs.editor)
      this.editor = editor
      editor.config.height = this.height
      editor.config.placeholder = this.placeholder
      // change事件
      editor.config.onchange = (html) => {
        this.$emit('change', html, editor)
      }
      // 插入网络图片事件
      editor.config.linkImgCallback = (src, alt, href) => {
        this.$emit('linkImg', src, alt, href)
      }
      // 插入网络视频
      editor.config.onlineVideoCallback = (video) => {
        this.$emit('onlineVideo', video)
      }
      // 自定义alert弹窗
      editor.config.customAlert = this.alertSet
      // 关闭粘贴样式的过滤
      editor.config.pasteFilterStyle = false
      // 图片上传设置
      const uploadImgConfig = this.setUpload()
      Object.keys(uploadImgConfig).forEach((key) => {
        editor.config[key] = uploadImgConfig[key]
      })
      const uploadVideoConfig = this.setUpload(false)
      Object.keys(uploadVideoConfig).forEach((key) => {
        editor.config[key] = uploadVideoConfig[key]
      })
      editor.create()
      if (this.defaultHtml) {
        editor.txt.html = this.defaultHtml
      }
    },
    // alert弹窗设置
    alertSet(message, type) {
      Message({
        type,
        message,
      })
    },
    setUpload(isImg = true) {
      let loading = this.localLoading()
      const showError = () => {
        this.$message.error(arguments[2])
        loading.close()
      }
      const hooks = {
        before: loading.show,
        success: function (xhr) {
          loading.close()
        },
        fail: showError,
        error: showError,
        timeout() {
          this.$message.error('图片上传超时，请重试')
        },
      }
      // 默认设置
      const defaults = {
        server: '',
        maxSize: isImg ? 2 * 1024 * 1024 : 1 * 1024 * 1024 * 1024,
        accept: isImg ? ['jpg', 'jpeg', 'png', 'gif', 'bmp'] : ['mp4'],
        maxLength: 5,
        params: {},
        header: {},
        timeout: isImg ? 10 * 1000 : 1000 * 60 * 5,
        hooks: {},
      }

      const setting = Object.assign(
        {},
        defaults,
        isImg ? this.uploadImgServer : this.uploadVideoServer
      )
      Object.keys(hooks).forEach((key) => {
        if (!(key in setting.hooks)) {
          setting.hooks[key] = hooks[key]
        }
      })
      return Object.keys(setting).reduce((obj, key) => {
        // wangEditor的设置大部分都是以uploadXX开头并使用驼峰命名
        const newKey = isImg
          ? 'uploadImg'
          : 'uploadVideo' + key.charAt(0).toUpperCase() + key.substr(1)
        obj[newKey] = setting[key]
        return obj
      }, {})
    },
    setUploadVideo() {},
    localLoading() {
      let loading = null
      return {
        show() {
          loading = this.$loading({
            lock: true,
            text: '图片上传中...',
            spinner: 'el-icon-loading',
            background: 'rgba(0, 0, 0, 0.7)',
          })
        },
        close() {
          if (loading) {
            loading.close()
            loading = null
          }
        },
      }
    },
  },
}
</script>
<style lang="scss" scoped></style>
